#include "fcgi_server.h"

#include <pthread.h>
#include <fcgi_stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcgiapp.h>
#include <signal.h>
#include <getopt.h>
#include <errno.h>

#include "web_log.h"
#include "web_internal.h"
#include "web_login.h"
#include "web_cmd.h"

int cgi_sock = -1;
int daemon_mode = 0;  // 默认不以守护进程方式运行
int stop_mode = 0;    // 默认不是停止模式

#define PID_FILE "/tmp/fcgiserver.pid"

// Signal handler to clean up socket file on exit
void cleanup_handler(int sig) {
    log_info("Received signal %d, cleaning up and exiting...", sig);
    if (cgi_sock >= 0) {
        close(cgi_sock);
        cgi_sock = -1;
    }
    unlink(FCGI_SOCKET_PATH);
    unlink(PID_FILE);  // 删除PID文件
    log_info("Cleanup complete, exiting");
    exit(0);
}

// 将当前进程的PID写入PID文件
int write_pid_file() {
    FILE *fp;
    pid_t pid = getpid();
    
    // 打开PID文件
    fp = fopen(PID_FILE, "w");
    if (fp == NULL) {
        log_error("Failed to open PID file: %s", strerror(errno));
        return -1;
    }
    
    // 写入PID
    fprintf(fp, "%d\n", pid);
    fflush(fp);  // 确保数据被写入磁盘
    fclose(fp);
    
    // 设置PID文件权限
    if (chmod(PID_FILE, 0644) < 0) {
        log_error("Failed to set PID file permissions: %s", strerror(errno));
        return -1;
    }
    
    log_info("PID file created: %s (PID: %d)", PID_FILE, pid);
    return 0;
}

// 停止运行中的服务
int stop_running_server() {
    FILE *fp;
    pid_t pid;
    int ret = -1;
    
    // 打开PID文件
    fp = fopen(PID_FILE, "r");
    if (fp == NULL) {
        log_error("Failed to open PID file: %s. Is the server running?", strerror(errno));
        return -1;
    }
    
    // 读取PID
    char pid_str[32] = {0};
    if (fgets(pid_str, sizeof(pid_str), fp) == NULL) {
        log_error("Failed to read PID from file: %s", strerror(errno));
        fclose(fp);
        return -1;
    }
    
    // 转换PID字符串为整数
    pid = atoi(pid_str);
    if (pid <= 0) {
        log_error("Invalid PID read from file: %s", pid_str);
        fclose(fp);
        return -1;
    }
    fclose(fp);
    
    log_info("Stopping fcgiServer with PID: %d", pid);
    
    // 发送SIGTERM信号
    if (kill(pid, SIGTERM) == 0) {
        // 等待进程退出
        int max_wait = 10; // 最多等待10秒
        while (max_wait-- > 0) {
            if (kill(pid, 0) < 0) {
                if (errno == ESRCH) {
                    // 进程已经退出
                    ret = 0;
                    break;
                }
            }
            sleep(1);
        }
        
        if (ret != 0) {
            log_error("Process did not terminate within timeout, sending SIGKILL");
            kill(pid, SIGKILL);
            ret = 0;
        }
    } else {
        if (errno == ESRCH) {
            log_error("No process with PID %d is running", pid);
            // 进程不存在，可能已经退出，删除PID文件
            unlink(PID_FILE);
            ret = 0;
        } else {
            log_error("Failed to send signal to process: %s", strerror(errno));
        }
    }
    
    // 删除PID文件
    if (ret == 0) {
        unlink(PID_FILE);
        log_info("fcgiServer stopped successfully");
    }
    
    return ret;
}

// 将进程转换为守护进程
void daemonize() {
    pid_t pid;
    
    // 创建子进程
    pid = fork();
    
    // 创建子进程失败
    if (pid < 0) {
        log_error("Failed to fork daemon process");
        exit(1);
    }
    
    // 父进程退出
    if (pid > 0) {
        exit(0);
    }
    
    // 子进程继续
    
    // 创建新会话，使子进程成为会话首进程
    if (setsid() < 0) {
        log_error("Failed to create new session");
        exit(1);
    }
    
    // 忽略SIGHUP信号
    signal(SIGHUP, SIG_IGN);
    
    // 再次fork，确保进程不是会话首进程，防止获取控制终端
    pid = fork();
    if (pid < 0) {
        log_error("Failed to fork daemon process (second fork)");
        exit(1);
    }
    if (pid > 0) {
        exit(0);
    }
    
    // 更改工作目录到根目录
    if (chdir("/") < 0) {
        log_error("Failed to change working directory");
        exit(1);
    }
    
    // 重设文件创建掩码
    umask(0);
    
    // 关闭所有打开的文件描述符
    for (int i = 0; i < 1024; i++) {
        close(i);
    }
    
    // 重定向标准输入、输出和错误到/dev/null
    int fd = open("/dev/null", O_RDWR);
    if (fd < 0) {
        log_error("Failed to open /dev/null");
        exit(1);
    }
    
    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    
    if (fd > 2) {
        close(fd);
    }
    
    log_info("Process daemonized successfully with PID: %d", getpid());
}


int get_fcgx_envparams(FCGX_Request *request,fcgxEnvParams *envParams)
{
    char *contentLength = NULL;

    if (NULL == request || NULL == envParams) {
        return RT_ERR;
    }

    memset(envParams,0,sizeof(fcgxEnvParams));

    envParams->req = request;

    envParams->server_name = FCGX_GetParam("SERVER_NAME", request->envp);
    envParams->query_string = FCGX_GetParam("QUERY_STRING", request->envp);
    envParams->request_uri = FCGX_GetParam("REQUEST_URI", request->envp);
     
    contentLength = FCGX_GetParam("CONTENT_LENGTH", request->envp);
    if (NULL != contentLength) {
        envParams->content_Length = strtol(contentLength, NULL, 10);
    }
    envParams->request_method = FCGX_GetParam("REQUEST_METHOD", request->envp);



    return RT_OK;
}



int parse_query_string(char *query_string,queryStringInfo *queryInfos)
{
    
    if (NULL == query_string || NULL == queryInfos) {
        return RT_ERR;
    }

    memset(queryInfos,0,sizeof(queryStringInfo));

    // 添加版本参数解析
    extract_url_param(query_string,"version",queryInfos->version,QUERY_STRING_VALUE_MAX_LEN);
    extract_url_param(query_string,"method",queryInfos->method,QUERY_STRING_VALUE_MAX_LEN);
    extract_url_param(query_string,"func",queryInfos->func,QUERY_STRING_VALUE_MAX_LEN);

    // 如果没有指定版本，默认使用v1
    if (queryInfos->version[0] == '\0') {
        strncpy(queryInfos->version, "v1", QUERY_STRING_VALUE_MAX_LEN);
    }

    log_info("fcgiServer query version is %s, method is %s, func is %s",
             queryInfos->version, queryInfos->method, queryInfos->func);
    
    return RT_OK;
}

// 解析RESTful API路径
int parse_rest_api_path(char *uri, queryStringInfo *queryInfos)
{
    if (NULL == uri || NULL == queryInfos) {
        return RT_ERR;
    }

    // 设置默认值
    memset(queryInfos, 0, sizeof(queryStringInfo));
    strncpy(queryInfos->version, "v1", QUERY_STRING_VALUE_MAX_LEN);
    
    // 检查URI是否以/api/开头
    if (strncmp(uri, "/api/", 5) == 0) {
        char path[256];
        strncpy(path, uri + 5, sizeof(path) - 1); // 跳过"/api/"
        path[sizeof(path) - 1] = '\0';
        
        // 复制路径以便使用strtok
        char *path_copy = strdup(path);
        if (path_copy) {
            char *parts[4] = {NULL};  // v1, auth, login
            int i = 0;
            
            char *token = strtok(path_copy, "/");
            while (token != NULL && i < 4) {
                parts[i++] = token;
                token = strtok(NULL, "/");
            }
            
            // 解析版本、方法和功能
            if (i >= 1 && parts[0]) {
                strncpy(queryInfos->version, parts[0], QUERY_STRING_VALUE_MAX_LEN - 1);
                queryInfos->version[QUERY_STRING_VALUE_MAX_LEN - 1] = '\0';
            }
            if (i >= 2 && parts[1]) {
                strncpy(queryInfos->method, parts[1], QUERY_STRING_VALUE_MAX_LEN - 1);
                queryInfos->method[QUERY_STRING_VALUE_MAX_LEN - 1] = '\0';
            }
            if (i >= 3 && parts[2]) {
                strncpy(queryInfos->func, parts[2], QUERY_STRING_VALUE_MAX_LEN - 1);
                queryInfos->func[QUERY_STRING_VALUE_MAX_LEN - 1] = '\0';
            }
            
            free(path_copy);
        }
    }
    
    log_info("fcgiServer REST API path parsed: version is %s, method is %s, func is %s",
             queryInfos->version, queryInfos->method, queryInfos->func);
    
    return RT_OK;
}

//处理http请求的函数
void cgi_service(FCGX_Request *request) 
{
    char recvBuf[FCGX_URL_STRING_MAX_LEN];
    fcgxEnvParams envParams;
    queryStringInfo queryInfos;
    int parseResult = RT_ERR;

    if (RT_OK != get_fcgx_envparams(request,&envParams)) {
        web_respone_err(request,WEB_STATUE_STR_404);
        return;
    }

    // 首先尝试解析查询字符串
    if (envParams.query_string && envParams.query_string[0] != '\0') {
        parseResult = parse_query_string(envParams.query_string, &queryInfos);
    }
    
    // 如果查询字符串解析失败或者没有查询字符串，尝试解析RESTful API路径
    if (parseResult != RT_OK && envParams.request_uri && envParams.request_uri[0] != '\0') {
        parseResult = parse_rest_api_path(envParams.request_uri, &queryInfos);
    }
    
    // 如果两种解析方式都失败，返回错误
    if (parseResult != RT_OK) {
        web_respone_err(request, WEB_STATUE_STR_400);
        return;
    }

    //POST请求
 	if(strcmp(envParams.request_method, "POST") == 0){
        //post请求没有数据，不处理
        if(envParams.content_Length == 0 || envParams.content_Length >= FCGX_URL_STRING_MAX_LEN){
            web_respone_err(request, WEB_STATUE_STR_400);
            return;
        }

        FCGX_GetStr(recvBuf, envParams.content_Length + 1, envParams.req->in);

        log_info("fcgiServer request method: %s, URI: %s", envParams.request_method, envParams.request_uri);
        log_info("fcgiServer query string is %s", envParams.query_string ? envParams.query_string : "NULL");
        log_info("fcgiServer request param is %s, length is %d", recvBuf, envParams.content_Length);

        if (0 == strcmp(queryInfos.method,"auth") && 0 == strcmp(queryInfos.func,"login")) {
            log_info("Processing login request");
            
            // 检查API版本
            if (0 != strcmp(queryInfos.version, "v1")) {
                // 如果版本不匹配，返回错误响应
                struct json_object *error_object = json_object_new_object();
                if (error_object != NULL) {
                    json_object_object_add(error_object, "code", json_object_new_int(400));
                    json_object_object_add(error_object, "message", 
                        json_object_new_string("Unsupported API version. Please use v1"));
                    web_respone_json(envParams.req, error_object);
                    json_object_put(error_object);
                    return;
                } else {
                    web_respone_err(envParams.req, WEB_STATUE_STR_400);
                    return;
                }
            } else {
                web_process_login(&envParams, recvBuf, envParams.content_Length);
                return;
            }
        }

    } else if (strcmp(envParams.request_method, "GET") == 0){
        // 可以在这里添加GET请求的处理逻辑
        web_respone_err(request, WEB_STATUE_STR_400);
        return;
    } else {
        web_respone_err(request, WEB_STATUE_STR_400);
        return;
    }

    // 如果没有匹配到任何处理逻辑，返回404错误
    web_respone_err(request, WEB_STATUE_STR_404);
}
//线程函数，等待-处理不断循环
void *thread_cgi(void *param)
{
	int ret;
	FCGX_Request cgi_request;
	while(1){
		memset(&cgi_request, 0, sizeof(cgi_request));
	 	FCGX_InitRequest(&cgi_request, cgi_sock, 0);
	 	ret = FCGX_Accept_r(&cgi_request);
		if(ret == 0){
			cgi_service(&cgi_request);	//处理cgi request的请求。
			FCGX_Finish_r(&cgi_request);
		 }else{
	      		 printf("CGI accept fail\n");
		 }
	}
}

int main(int argc, char* argv[])
{
	int i;
	pthread_t id[CGI_THREAD_NUM];
    int opt;
    
    // 解析命令行参数
    static struct option long_options[] = {
        {"daemon", no_argument, 0, 'd'},
        {"stop", no_argument, 0, 's'},
        {0, 0, 0, 0}
    };
    
    while ((opt = getopt_long(argc, argv, "ds", long_options, NULL)) != -1) {
        switch (opt) {
            case 'd':
                daemon_mode = 1;
                break;
            case 's':
                stop_mode = 1;
                break;
            default:
                fprintf(stderr, "Usage: %s [-d|--daemon] [-s|--stop]\n", argv[0]);
                fprintf(stderr, "  -d, --daemon    Run as daemon\n");
                fprintf(stderr, "  -s, --stop      Stop running server\n");
                exit(EXIT_FAILURE);
        }
    }
    
    // 如果是停止模式，则停止运行中的服务并退出
    if (stop_mode) {
        log_init(FCGI_SERVER_LOG_FILE_NAME);
        log_info("Stopping fcgiServer...");
        int ret = stop_running_server();
        return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
    }

    // Register signal handlers for cleanup
    signal(SIGTERM, cleanup_handler);
    signal(SIGINT, cleanup_handler);

    log_init(FCGI_SERVER_LOG_FILE_NAME);

	log_info("fcgi server init...");
    
    // 如果指定了守护进程模式，则将进程转换为守护进程
    if (daemon_mode) {
        log_info("Running in daemon mode");
        daemonize();
        
        // 在守护进程模式下，如果PID文件创建失败，则退出程序
        if (write_pid_file() != 0) {
            log_error("Failed to create PID file in daemon mode, exiting");
            exit(EXIT_FAILURE);
        }
        log_info("PID file created successfully with PID: %d", getpid());
    } else {
        // 非守护进程模式下，创建PID文件但失败不退出
        if (write_pid_file() != 0) {
            log_error("Failed to create PID file, continuing anyway");
        } else {
            log_info("PID file created successfully with PID: %d", getpid());
        }
    }
    
    web_cmd_init();
    /*web_cmd_add_user("admin","123456");
    web_cmd_verity_user("admin","1234565");
    web_cmd_verity_user("admin1","123456");
    web_cmd_verity_user("admin","123456");*/
	
	FCGX_Init();
	
	// Remove existing socket file if it exists
	unlink(FCGI_SOCKET_PATH);
	
	cgi_sock = FCGX_OpenSocket(FCGI_SOCKET_PATH, 512);
	if(cgi_sock < 0) {
		log_info("open FCGX socket failed\n");
		return -1;
	}
	
	// Set socket file permissions to allow Nginx access
	if (chmod(FCGI_SOCKET_PATH, 0666) < 0) {
		log_info("chmod socket file failed\n");
		close(cgi_sock);
		unlink(FCGI_SOCKET_PATH);
		return -1;
	}
	
	for(i = 1; i < CGI_THREAD_NUM; i++) {
	 	pthread_create(&id[i], NULL, thread_cgi, (void*)&i);
	}

    log_info("fcgi server init Finish");

    thread_cgi(0);
	return 0;
}